package de.westranger.forex.trading.genetic.allel.fitness;

import java.text.ParseException;

import de.westranger.forex.trading.genetic.ContentResolver;
import de.westranger.forex.trading.genetic.EvaluateOperator;
import de.westranger.forex.trading.genetic.allel.chromosom.CompositeChromosom;
import de.westranger.forex.trading.genetic.allel.operator.TerminalSymbol;
import de.westranger.forex.trading.genetic.allel.operator.UnknownOperatorException;

public final class MoneyManagedFitnessV2 {
	private final ContentResolver conRes;
	private final int valueCount;
	private final EvaluateOperator eval;
	private final SignalType[] signal;
	private final double percentage;
	private final double money;
	private double stopLoss = Double.POSITIVE_INFINITY;
	private final double leverage;
	private double takeProfit = Double.POSITIVE_INFINITY;
	
	private double voteTreshhold = 5.0*(1.0/5.0);
	
	public MoneyManagedFitnessV2(final ContentResolver conRes,final double money,final double percentage,final double leverage){
		this.conRes = conRes;

		this.valueCount = conRes.getValueCount();
		this.eval = new EvaluateOperator(conRes);
		this.signal = new SignalType[this.valueCount];	
		this.money = money;
		this.percentage = percentage;
		
		this.leverage = leverage;
	}

	public CompositeFitness computeFitness(final CompositeChromosom[] nodeBuy) throws UnknownOperatorException, ParseException{
//		for(int i=0;i<nodeBuy.length;i++){
//			System.out.println(nodeBuy[i].getStoploss()+"\t"+nodeBuy[i].getTakeProfit());
//			this.stopLoss += nodeBuy[i].getStoploss();
//			this.takeProfit += nodeBuy[i].getTakeProfit();
//		}
//		
//		this.stopLoss /= nodeBuy.length;
//		this.takeProfit /= nodeBuy.length;

		for(int i=0;i<nodeBuy.length;i++){
			System.out.println(nodeBuy[i].getStoploss()+"\t"+nodeBuy[i].getTakeProfit());
			this.stopLoss = 119.0;
			this.takeProfit = 41.0;
		}		
		
		System.out.println(this.stopLoss);
		System.out.println(this.takeProfit);
		
		final ProfitManager proMgr = new ProfitManager(conRes, this.leverage, this.percentage, this.stopLoss, this.money,this.takeProfit);
		final boolean[] buys = new boolean[nodeBuy.length];
		boolean buy = false;
		
		this.eval.setTime(0);
		
		for(int i=0;i<buys.length;i++){
			buys[i] = this.eval.evaluate(nodeBuy[i].getNodeBuy());
		}
		
		boolean firstBuy = combineSignals(buys) ? true : false;

		signal[0] = SignalType.NOTHING;
		
		for(int i=1;i<this.valueCount;i++){
			this.eval.setTime(i);

//			System.out.print(conRes.resolve(TerminalSymbol.TIME.getValue(), i)+"\t");
			for(int j=0;j<buys.length;j++){
				buys[j] = this.eval.evaluate(nodeBuy[j].getNodeBuy());
//				System.out.print(buys[j]+"\t");
			}
//			System.out.println();
			
			buy = combineSignals(buys);

			if(firstBuy && !buy){
				firstBuy = false;
			}else if(firstBuy){
				buy = false;
			}

			signal[i] = buy ? SignalType.BUY : SignalType.NOTHING;
//			System.out.println(signal[i]);
		}

		double profit = this.money;
		int transStart = this.signal[0] != SignalType.NOTHING ? 0 : -1;
		double posTrade = 0;
		double negTrade = 0;
		double avgNegProfit = 0.0;
		double avgPosProfit = 0.0;
		double counterBuy = 0.0;
		double counterSell = 0.0;
		double tmp = 0.0;

			for(int i=1;i<this.signal.length;i++){
				
				boolean trade = false;
				if(signal[i] != signal[i-1] || i-1 == this.signal.length-1){
					if(signal[i-1] == SignalType.BUY){
						trade = true;
						tmp = proMgr.pendingBuyOrder(transStart, i);
						counterBuy++;
						System.out.println(" buy von\t" + transStart  +"\tbis\t" + i + "\t" + proMgr.getCounterStopLoss() + "\t" + proMgr.getCounterTakeProfit() + "\t" + tmp);
					}else if(signal[i-1] == SignalType.SELL){
						trade = true;
						tmp = proMgr.pendingSellOrder(transStart, i);
						counterSell++;
						//System.out.println(" sell von\t" + transStart  +"\tbis\t" + i + "\t" + proMgr.getCounterStopLoss() + "\t" + proMgr.getCounterTakeProfit() + "\t" + tmp);
					}else{
						tmp = 0.0;
					}
					profit += tmp;
					
					if(profit < 0.000001){ // is this possible ?
						profit = 0.000001;
						break; // this is it, we dont have any money left
					}

					if(trade){
						if(tmp > 0.0){
							posTrade++;
							avgPosProfit += tmp;
						}else if(tmp < 0.0){
							negTrade++;
							avgNegProfit += tmp;
						}					
						trade = false;
					}

					transStart = this.signal[i] != SignalType.NOTHING ? i : -1;
				}
				//System.out.println();
			}
		
//		profit -= this.money;
		
		if(profit <= 0.000001){
			profit = 0.000001;
		}
		
		avgPosProfit /= (double)posTrade;
		avgNegProfit /= (double)negTrade;

		// we penalize everything which does not trade
		if (Double.isNaN(avgPosProfit)) {
			avgPosProfit = 0.0;
			posTrade = 0.0;
		}

		if (Double.isNaN(avgNegProfit)) {
			avgNegProfit = 0.0;
			negTrade = 0.0;
		}
		return new CompositeFitness(profit,avgPosProfit,avgNegProfit,posTrade,negTrade,proMgr.getCounterStopLoss(),proMgr.getCounterTakeProfit(),counterBuy,counterSell,proMgr.getSumBuySellRatio(),proMgr.getProdBuySellRatio());
	}
	
	private boolean combineSignals(final boolean[] signals){
		boolean result = false;
		int counter = 0;
		
		for(boolean b:signals){
			if(b){
				counter++;
			}
		}
		
		if(counter >= (double)signals.length*this.voteTreshhold){
			result = true;
		}

		return result;
	}

	public double getVoteTreshhold() {
		return voteTreshhold;
	}

	public void setVoteTreshhold(final double voteTreshhold) {
		this.voteTreshhold = voteTreshhold;
	}
}
